package galaxy.app.network.rpc.server;

import java.util.List;

import galaxy.app.Galaxy;
import galaxy.app.log.LogHelper;
import galaxy.app.network.rpc.codec.RpcDecoder;
import galaxy.app.network.rpc.codec.RpcEncoder;
import galaxy.app.network.rpc.handler.GameEventHandler;
import galaxy.app.network.rpc.handler.HeartbeatHandler;
import galaxy.app.network.rpc.handler.RegisterNodeHandler;
import galaxy.app.network.rpc.handler.RequestHandler;
import galaxy.app.system.ConfigComponent;
import galaxy.kernel.component.ECSComponent;
import galaxy.kernel.system.AbstractECSSystem;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.timeout.IdleStateHandler;

public class NettyRpcServerSystem extends AbstractECSSystem {
    @Override
    public void start() {
        List<ECSComponent>  list = Galaxy.components().get(NettyRpcServerComponent.class);
        if(list==null || list.isEmpty() ){
            return;
        }
        ConfigComponent config = Galaxy.components().getSingle(ConfigComponent.class);
        list.forEach(c -> {
            NettyRpcServerComponent nc = (NettyRpcServerComponent)c;
            nc.port = config.currentNode.getRpcPort();
        });
        
        list.forEach(component->{
            startServer((NettyRpcServerComponent)component);

        });
    }

    private void startServer(NettyRpcServerComponent c) {
        ServerBootstrap bootstrap = new ServerBootstrap();
        try {
            bootstrap.group(NettyRpcServerComponent.bossGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel channel) throws Exception {
                            ChannelPipeline cp = channel.pipeline();
                            cp.addLast(new LengthFieldBasedFrameDecoder(1024 * 1024, 0, 4, 0, 0));
                            cp.addLast(new RpcDecoder());
                            cp.addLast(new RpcEncoder());
                            cp.addLast(new IdleStateHandler(0, 0, 360));
                            cp.addLast(new RegisterNodeHandler(Galaxy.admin()));
                            cp.addLast(new RequestHandler());
                            cp.addLast(new GameEventHandler());
                            cp.addLast(new HeartbeatHandler());
                        }
                    })
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .option(ChannelOption.SO_BACKLOG, 12000);
            //.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)

            c.channelFuture = bootstrap.bind(c.port);
            LogHelper.info("-----> RPC connector started on port {}", c.port);
        } catch (Exception ex) {
            LogHelper.error("{}", ex);
        }
    } 
}
